package club.janna.netty.qps;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.concurrent.FastThreadLocal;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Server {
    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup boosGroup = new NioEventLoopGroup(1);
        EventLoopGroup workGroup = new NioEventLoopGroup();
        EventLoopGroup bizGroup = new NioEventLoopGroup(500);

        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(boosGroup, workGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ch.pipeline().addLast(bizGroup, BizHandler.INSTANCE);
                    }
                });
        ChannelFuture future = bootstrap.bind(8080).sync();
        System.out.println("启动成功，8080");
        future.channel().closeFuture().sync();
    }

    /**
     * 业务处理器
     */
    @ChannelHandler.Sharable
    private static class BizHandler extends ChannelInboundHandlerAdapter {

        public static final BizHandler INSTANCE = new BizHandler();

//        private static final ExecutorService bizPool = Executors.newFixedThreadPool(30);

        private static final FastThreadLocal<Random> THREAD_LOCAL = new FastThreadLocal<Random>() {
            @Override
            protected Random initialValue() throws Exception {
                return new Random();
            }
        };

        private BizHandler() {}

        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            // 读取数据
            ByteBuf byteBuf = (ByteBuf) msg;
            byte[] bytes = new byte[byteBuf.readableBytes()];
            byteBuf.readBytes(bytes);
            byteBuf.release();

//            bizPool.execute(() -> {
//
//            });

            // 业务操作
            byte[] rs = bizOp(bytes);

            // 返回数据
            ByteBuf byteBuf1 = ctx.alloc().directBuffer(rs.length);
            byteBuf1.writeBytes(rs);
            ctx.writeAndFlush(byteBuf1);
        }

        /**
         * 业务操作
         */
        private byte[] bizOp(byte[] bytes) {
            Random random = THREAD_LOCAL.get();
            int i = random.nextInt(1000);
            /**
             * 模拟业务延迟
             * 90%      -> 1ms
             * 95%      -> 10ms
             * 99%      -> 100ms
             * 99.9%    -> 1000ms
             */
            int delay;
            if(i <= 900)
                delay = 1;
            else if(i <= 950)
                delay = 10;
            else if(i <= 990)
                delay = 100;
            else
                delay = 1000;
            try {
                Thread.sleep(delay);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return bytes;
        }
    }
}
